import { Inject, Provide } from '@midwayjs/decorator';
import { BaseService } from '@cool-midway/core';
import { CacheManager } from '@midwayjs/cache';
import getenPassword = require('newzf-rsa');
import * as cheerio from 'cheerio';
import http = require('urllib');

/**
 * 新版正方
 */
@Provide()
export class NewzfCommonService extends BaseService {

    // 缓存管理器
    @Inject()
    cacheManager: CacheManager;

    /**
     * 获取cookie
     * @param userId 用户ID
     * @param url 学校URL
     * @param loginType 登录类型
     * @param username 用户名
     * @param password 密码
     * @param isLogin 是否登录
     */
    async get_cookie(userId, url, loginType, username, password, isLogin?) {
        try {
            if (isLogin) {
                await this.cacheManager.del(`jw:token:${userId}`);
            }
            const cookie = await this.cacheManager.get(`jw:token:${userId}`);
            if (cookie) return { success: true, message: '已登录', cookie };
            let result = null;
            switch (loginType) {
                case 0:
                    result = await this.login(url, username, password);
                    break;
                case 1:
                    result = await this.login(url, username, password);
                    break;
            }
            if (!result.success) return { success: false, message: result.message, cookie: null };
            await this.cacheManager.set(`jw:token:${userId}`, result.data, { ttl: 600 });
            return {
                success: true,
                message: result.message,
                cookie: result.data
            };
        } catch (error) {
            return {
                success: false,
                message: '系统维护中',
                cookie: []
            }
        }
    }

    /**
     * 登录
     * @param url 学校URL
     * @param username 用户名
     * @param password 密码
     */
    async login(url, username, password) {
        try {
            const { success, modulus, exponent, cookie } = await this.get_public_key(url);
            if (!success) return { success: false, message: '系统维护中', data: null };
            const csrfToken = await this.get_csrftoken(url, cookie);
            if (!csrfToken) return { success: false, message: 'csrfToken获取失败', data: null };
            const enpassword = getenPassword(password, modulus, exponent);
            const { headers, data } = await http.request(`${url}/xtgl/login_slogin.html?time=${new Date().getTime()}`, {
                method: 'POST',
                timeout: 10000,
                headers: {
                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                    'Accept-Encoding': 'gzip, deflate, br',
                    'Accept-Language': 'zh-CN,zh;q=0.9',
                    'Connection': 'keep-alive',
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Cookie': `${cookie}`,
                    'Origin': `${url}`,
                    'Referer': `${url}/xtgl/login_slogin.html?time=${new Date().getTime()}`,
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/101.0.4951.54 Safari/537.36'
                },
                data: {
                    'csrftoken': csrfToken,
                    'yhm': username,
                    'mm': enpassword
                }
            });
            const regValue = '用户名或密码不正确';
            if (data.toString().indexOf(regValue) > 0) return { success: false, message: regValue, data: null };
            return {
                success: true,
                message: '登录成功',
                data: headers['set-cookie'][1].split(';')[0]
            }
        } catch (error) {
            return { 
                success: false, 
                message: '系统维护中', 
                data: [] 
            };
        }
    }

    /**
     * 公共密钥
     * @param url 学校URL
     */
    async get_public_key(url: string) {
        try {
            const { headers, status, data } = await http.request(`${url}/xtgl/login_getPublicKey.html?time=${new Date().getTime()}`, {
                method: 'GET',
                timeout: 10000,
                headers: {
                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                    'Accept-Encoding': 'gzip, deflate, br',
                    'Accept-Language': 'zh-CN,zh;q=0.9',
                    'Connection': 'keep-alive',
                    'X-Requested-With': 'XMLHttpRequest',
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/101.0.4951.54 Safari/537.36'
                }
            });
            if (status !== 200) return { success: false };
            const { modulus, exponent } = JSON.parse(data);
            return {
                success: true,
                modulus,
                exponent,
                cookie: headers['set-cookie'][0].split(';')[0]
            }
        } catch (error) {
            return { success: false };
        }
    }

    /**
    * 获取csrfToken
    * @param url URL地址
    * @param cookie cookie
    */
    async get_csrftoken(url: string, cookie: string) {
        try {
            const { status, data } = await http.request(`${url}/xtgl/login_slogin.html?time=${new Date().getTime()}`, {
                method: 'GET',
                timeout: 10000,
                headers: {
                    'Accept': 'application/json, text/javascript, */*; q=0.01',
                    'Accept-Encoding': 'gzip, deflate, br',
                    'Accept-Language': 'zh-CN,zh;q=0.9',
                    'Connection': 'keep-alive',
                    'Cookie': `${cookie}`,
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36'
                },
            });
            if (status !== 200) return false;
            const $ = cheerio.load(data);
            const csrftoken = $('#csrftoken')[0].attribs.value;
            return csrftoken;
        } catch (error) {
            return false;
        }
    }
}
